package cn.starrysky108.simpleerp.core.config;

import cn.starrysky108.simpleerp.core.constant.SecurityConstants;
import cn.starrysky108.simpleerp.core.security.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsUtils;

/**
 * spring security配置类
 *
 * @author Carl Lee
 */
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 登录成功处理器
     */
    private final LoginSuccessHandler successHandler;
    /**
     * 登录失败处理器
     */
    private final LoginFailureHandler failureHandler;
    /**
     * 全局认证失败处理器
     */
    private final AuthenticationEntryPointImpl unauthorizedHandler;
    /**
     * jwt认证失败处理器
     */
    private final JwtAccessDeniedHandler deniedHandler;
    /**
     * 用户认证逻辑
     */
    private final UserDetailsService userDetailsService;
    private final String[] URL_WHITELIST = {
            "/auth/**",
            "/pub/**",
            "/system/files/**",
    };

    @Autowired
    public SecurityConfig(LoginFailureHandler failureHandler, AuthenticationEntryPointImpl jwtAuthenticationEntryPoint,
                          JwtAccessDeniedHandler deniedHandler, LoginSuccessHandler successHandler,
                          UserDetailsService userDetailsService) {
        this.failureHandler = failureHandler;
        this.unauthorizedHandler = jwtAuthenticationEntryPoint;
        this.deniedHandler = deniedHandler;
        this.successHandler = successHandler;
        this.userDetailsService = userDetailsService;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //开启cors，禁用csrf攻击防护，以支持跨域访问
        http.cors().and().csrf().disable()
                //异常处理器
                .exceptionHandling()
                .authenticationEntryPoint(unauthorizedHandler)
                .accessDeniedHandler(deniedHandler)
                //禁用session
                .and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                //关闭fram请求拦截
                .and()
                .headers().frameOptions().disable()
                //拦截规则
                .and()
                .authorizeRequests()
                //白名单
                .antMatchers(URL_WHITELIST).permitAll()
                //特殊处理
                .antMatchers("/auth/logout").authenticated()
                //测试接口
                .antMatchers("/test/**").permitAll()
                .antMatchers("/swagger-*/**", "/*/api-docs").anonymous()
                .antMatchers("/druid/**").permitAll()
                //其他链接全部需要进行认证
                .anyRequest().authenticated()
                //登录配置,使用form表单,默认使用内置的UsernamePasswordAuthenticationFilter进行拦截
                .and()
                .formLogin()
                .loginProcessingUrl(SecurityConstants.AUTH_LOGIN_URL)
                .failureHandler(failureHandler)
                .successHandler(successHandler)
                //配置jwt拦截器
                .and()
                .addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);

    }

    /**
     * 身份认证接口
     */

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
    }

    /**
     * 配置静态资源直接绕过spring security
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring()
                //调试
                .antMatchers("/xrebel/**")
                //系统公共资源
                .antMatchers("/uploads/**", "/static/**");
    }

    /**
     * 注入密码编码器
     */
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 解决 无法直接注入 AuthenticationManager
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
    @Bean
    public JwtAuthenticationFilter jwtAuthenticationFilter(){
        return new JwtAuthenticationFilter(userDetailsService);
    }
}
